package com.myk.game.heroscuffle.game;

import androidx.annotation.IntRange;
import androidx.annotation.NonNull;

import com.myk.game.heroscuffle.data.HeroParam;
import com.myk.game.heroscuffle.events.GameEvent_HeroAttack;
import com.myk.game.heroscuffle.events.GameEvent_HeroDead;
import com.myk.game.heroscuffle.events.HeroEvent_AfterAction;
import com.myk.game.heroscuffle.events.HeroEvent_AfterBeAttack;
import com.myk.game.heroscuffle.events.HeroEvent_AfterDoAttack;
import com.myk.game.heroscuffle.events.HeroEvent_BeforeAction;
import com.myk.game.heroscuffle.events.HeroEvent_BeforeDoAttack;
import com.myk.game.heroscuffle.events.HeroEvent_SufferDamage;
import com.myk.game.heroscuffle.utils.RdmPropUtil;
import com.myk.game.heroscuffle.utils.SC;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 英雄基类
 */
public abstract class Hero {

    public final String NAME;   //英雄名称
    public final String DESCRIPTION; //英雄描述
    public Element ELE;   //英雄元素属性
    public final int HP;    //基础面板生命值
    public final int ATK;   //基础面板攻击力
    public final int DEF;   //基础面板防御力
    public final List<Skill> SKILLS; //英雄技能列表
    public final List<Sign> SIGNS; //英雄的状态标志
    public Game game; //当前游戏对象引用
    public HeroMind mind; //英雄的ai思考中心
    public HeroState state; //英雄的游戏中状态
    public HeroEvents event; //英雄的事件回调中心
    public int hp; //当前生命值
    public int atk; //当前攻击力
    public int def; //当前防御力

    public Hero(String NAME, String DESCRIPTION, Element ELE,
                @IntRange(from = HeroParam.MIN_HP, to = HeroParam.MAX_HP) int HP,
                @IntRange(from = HeroParam.MIN_ATK, to = HeroParam.MAX_ATK) int ATK,
                @IntRange(from = HeroParam.MIN_DEF, to = HeroParam.MAX_DEF) int DEF,
                Skill... skills) {
        this.NAME = NAME;
        this.DESCRIPTION = DESCRIPTION;
        this.ELE = ELE;
        this.HP = HP;
        this.ATK = ATK;
        this.DEF = DEF;
        this.SKILLS = new ArrayList<>(Arrays.asList(skills));
        this.SIGNS = new ArrayList<>();
    }

    /**
     * 获取被引号包围的名字
     */
    public final String getObviousName() {
        return SC.QUO + NAME + SC.QUO;
    }

    /**
     * 返回英雄初始面板信息文本
     */
    public final String getOriginInfo() {
        StringBuilder info = new StringBuilder(NAME + "(" + ELE.text + ") " + HP + "/" + ATK + "/" + DEF);
        for (int i = 0; i < SKILLS.size(); i++) {
            if (i == 0) {
                info.append("/");
            }
            else {
                info.append(",");
            }
            info.append(SKILLS.get(i).SKILL_NAME);
        }
        return info.toString();
    }

    /**
     * 获取详细的格式化的英雄介绍，包含其技能的介绍。
     */
    public final String getDetailDescription() {
        StringBuilder info = new StringBuilder();
        info.append(getObviousName());
        info.append("\n");
        info.append("[英雄介绍]：");
        info.append(SC.TLI);
        info.append(DESCRIPTION);
        if (SKILLS.size() > 0) {
            info.append("\n");
            info.append("[技能介绍]：");
        }
        for (Skill skill : SKILLS) {
            info.append(SC.TLI);
            info.append(SC.QUO);
            info.append(skill.SKILL_NAME);
            info.append(",");
            if (skill.COOL_DOWN > 0) {
                info.append("冷却时间").append(skill.COOL_DOWN).append("回合，");
            }
            if (skill.TIMES_LIMIT < Integer.MAX_VALUE) {
                info.append("限制使用").append(skill.TIMES_LIMIT).append("次，");
            }
            info.append(skill.DESCRIPTION);
            info.append(SC.QUO);
        }
        return info.toString();
    }

    /**
     * 获取处于游戏中的状态的详细信息文本
     */
    public final String getStateInfo() {
        StringBuilder info = new StringBuilder(NAME + "(" + ELE.text + ")  hp:" + hp + "/" + HP + "  atk:" + atk + "  def:" + def + (state.isPlayer ? " *" : ""));
        if (SKILLS.size() > 0 || SIGNS.size() > 0) {
            info.append(SC.TLI);
        }
        for (Skill skill : SKILLS) {
            info.append(skill.SKILL_NAME).append(skill.isReady() ? "√" : "×").append("  ");
        }
        info.append("    ");
        for (Sign sign : SIGNS) {
            info.append(sign.getObviousName());
            info.append("  ");
        }
        return info.toString();
    }

    /**
     * 英雄召唤方法
     */
    public final void summon(Game game) {
        this.game = game;
        initHeroMind();
        this.state = new HeroState();
        this.event = new HeroEvents();
        this.hp = HP;
        this.atk = ATK;
        this.def = DEF;
        for (Skill skill : this.SKILLS) {
            skill.init(this);
        }
        onSummon();
    }

    /**
     * 初始化定义英雄ai
     */
    public void initHeroMind() {
        this.mind = new HeroMind(this);
        mind.setDefaultAttackedSelector();
    }

    /**
     * 当英雄召唤上场时回调，
     */
    public void onSummon() {

    }

    /**
     * 收到任何伤害后，都要立即进行死亡检查
     */
    public final boolean checkDeath() {
        game.ui.printMsg("hp剩余" + hp);
        if (hp > 0) {
            game.ui.printMsg("。");
            game.ui.sleepShortly();
            return false;
        }
        else {
            game.ui.printMsg("，");
            game.ui.sleepShortly();
            game.ui.printMsg(getObviousName() + "死亡。");
            game.ui.sleepShortly();
            state.setDeath(); //切换为死亡状态
            return true;
        }
    }

    /**
     * 当角色死亡离场时
     */
    public void onDeath() {

    }

    /**
     * 英雄准备开始自己的回合
     */
    public final void preAction() {
        if (state.isAlive) {
            updateSign(); //更新英雄标记
        }
        if (state.isAlive) {
            updateSkill(); //更新英雄技能
        }
        if (state.isAlive) {
            event.onBeforeAction.sendRun(new HeroEvent_BeforeAction(this));
        }
        if (state.isAlive) {
            onPreAction(); //准备开始回合回调
        }
    }

    /**
     * 当英雄回合开始时回调
     */
    public void onPreAction() {

    }

    /**
     * 清除行动状态
     */
    public final void clearActioned() {
        state.isActioned = false;
    }

    /**
     * 本回合英雄状态改为已行动
     */
    public final void setActioned() {
        state.isActioned = true;
    }

    /**
     * 英雄回合结束后
     */
    public final void overAction() {
        if (state.isAlive) {
            onOverAction();
            event.onAfterAction.sendRun(new HeroEvent_AfterAction(this));
        }
    }

    /**
     * 当英雄回合结束后回调
     */
    public void onOverAction() {

    }

    /**
     * 英雄自己的性格决定行动
     */
    public final void autoActionSelect() {
        onAutoSelectAction();
    }

    /**
     * （自定义）英雄自己的性格决定行动时
     */
    public void onAutoSelectAction() {
        doAttackActionStart(autoSelectAttacked()); //默认就只会普通攻击
    }

    /**
     * 英雄选择普攻目标
     */
    public final Attacked autoSelectAttacked() {
        return mind.attackedSelector.onAutoSelectAttacked();
    }

    /**
     * 当英雄接收到玩家的普攻指定时
     */
    public void onAcceptPlayerAttackAction(Attacked preAttacked) {
        if (RdmPropUtil.bingo(state.exactRate) || game.pool.getAliveCount() == 2) {
            Hero attacked = preAttacked.getTarget(); //系统默认选中的目标
            this.doAttackActionStart(new Attacked(attacked, "遵从指定去攻击"));
        }
        else {
            Hero attacked = game.pool.getAnyoneAliveHero(this, preAttacked.getTarget()); //另外选一个目标
            this.doAttackActionStart(new Attacked(attacked, "自作主张去攻击"));
        }
    }

    /**
     * 英雄准备开始进行普通攻击
     */
    public final void doAttackActionStart(@NonNull Attacked attacked) {
        Hero target = attacked.getTarget();
        String reason = attacked.getReason();
        game.ui.printlnMsg(this.getObviousName() + reason + target.getObviousName() + "，");
        game.ui.sleepShortly();
        event.onBeforeDoAttack.sendRun(new HeroEvent_BeforeDoAttack(this, target));
        onBeforeDoAttack(target); //回调默认实现
    }

    /**
     * 当英雄主动攻击前回调 （普攻行为已经确定了）
     */
    public void onBeforeDoAttack(Hero attacked) {
        attacked.beAttackActionStart(this); //重写记得回调此方法以继续流程
    }

    /**
     * 英雄被普通攻击行为开始
     */
    public final void beAttackActionStart(Hero attacker) {
        onBeforeBeAttack(attacker);
    }

    /**
     * 当英雄被普通攻击前回调（普攻行为已经确定了）
     */
    public void onBeforeBeAttack(Hero attacker) {
        //最终结算伤害还是要在被攻击者身上
        int damage = onCalculateDamage(attacker); //计算伤害量
        boolean isAttackToDeath = sufferDamage(attacker, null, null, damage); //造成了普攻伤害
        //确定被普攻了就要调用该方法让流程继续下去
        beAttackActionEnd(attacker, damage, isAttackToDeath);
    }

    /**
     * 英雄被普攻行为结束
     */
    public final void beAttackActionEnd(Hero attacker, int damage, boolean isToDeath) {
        //回调普攻事件给外界
        game.events.onHeroAttack.sendRun(new GameEvent_HeroAttack(attacker, this, damage, isToDeath));
        //被普攻回调,如果被打死了，就没有资格回调了
        if (!isToDeath) {
            //this.setEnemy(attacker);//记住最新攻击我的仇人，下回优先打回去
            game.recorder.record(game.round,attacker,this,HateRecorder.HATE_TYPE_ATTACK);
            this.onAfterBeAttack(attacker, damage);
            event.onAfterBeAttack.sendRun(new HeroEvent_AfterBeAttack(this, attacker)); //该英雄被攻击后的回调通知
        }
        //普攻事件已经发生，无法被取消了，所以必然要执行攻击者的普攻结束事件，以继续流程
        attacker.doAttackActionEnd(this, damage, isToDeath);
    }

    /**
     * 当英雄被普通攻击后回调（普攻行为已经完成了）
     */
    public void onAfterBeAttack(Hero attacker, int damage) {

    }

    /**
     * 普攻行为完成，进入结算流程
     */
    public final void doAttackActionEnd(Hero attacked, int damage, boolean isToDeath) {
        this.setPrey(attacked); //记住最新我攻击的猎物，下回还优先打他
        this.onAfterDoAttack(attacked, damage, isToDeath);
        event.onAfterDoAttack.sendRun(new HeroEvent_AfterDoAttack(this, attacked)); //该英雄完成攻击后的回调通知
        overAction(); //普攻完成触发行动完成回调
    }

    /**
     * 当英雄进行普通攻击后回调（普攻行为已经完成了）
     */
    public void onAfterDoAttack(Hero attacked, int damage, boolean isToDeath) {

    }

    /**
     * 判断指定技能是否可用，若可用返回该技能实例
     */
    public final Skill getUsableSkill(Class<? extends Skill> skillClass) {
        for (Skill skill : SKILLS) {
            if (skill.getClass() == skillClass) {
                if (skill.isReady()) {
                    return skill;
                }
            }
        }
        return null;
    }

    /**
     * 英雄使用技能
     */
    public final void useSkill(Skill skill) {
        onBeforeSkillTrigger(skill);
        skill.trigger();
        onAfterSkillTrigger(skill);
        overAction();
    }

    /**
     * 当该英雄有技能初始化时
     */
    public void onSkillInit(Skill skill) {
        skill.onInit(); //默认要有这句，重写onSkillInit时也要记得主动调用这句
    }

    /**
     * 更新技能状态
     */
    public final void updateSkill() {
        for (Skill skill : SKILLS) {
            skill.update();
        }
    }

    /**
     * 当该英雄的技能更新后
     */
    public void onAfterSkillUpdate(Skill skill) {

    }

    /**
     * 当该英雄使用技能前回调
     */
    public void onBeforeSkillTrigger(Skill skill) {

    }

    /**
     * 当该英雄使用技能后回调
     */
    public void onAfterSkillTrigger(Skill skill) {

    }

    /**
     * 给该英雄添加标记
     */
    public void pasteSign(Sign sign) {
        sign.paste(this);
    }

    /**
     * 更新标记状态
     */
    public void updateSign() {
        List<Sign> safeList = new ArrayList<>(SIGNS);
        for (Sign sign : safeList) {
            if (this.state.isAlive) {
                sign.update();
            }
        }
    }

    /**
     * 判断改英雄是否有该标记
     */
    public final boolean hasSign(Class<? extends Sign> signClass) {
        for (Sign sign : SIGNS) {
            if (sign.getClass() == signClass) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取英雄身上的指定标记
     */
    public final Sign getSign(Class<? extends Sign> signClass) {
        for (Sign sign : SIGNS) {
            if (sign.getClass() == signClass) {
                return sign;
            }
        }
        return null;
    }

    /**
     * 移除指定标记
     */
    public final void removeSign(Class<? extends Sign> signClass) {
        Sign waitRemove = null;
        for (Sign sign : SIGNS) {
            if (sign.getClass() == signClass) {
                waitRemove = sign;
            }
        }
        if (waitRemove != null) {
            waitRemove.remove(this);
        }
    }

    /**
     * 移除英雄身上所有标记
     */
    public final void clearAllSign() {
        int num = SIGNS.size(); //因为Sign的remove内部调用了SIGNS的remove(obj)，所以用这种方式来遍历删除保证不出错
        for (int i = 0; i < num; i++) {
            SIGNS.get(0).remove(this);
        }
    }

    /**
     * 计算伤害方法
     */
    public int onCalculateDamage(Hero attacker) {
        return attacker.atk - this.def;
    }

    /**
     * 受到伤害时的结算
     */
    public final boolean sufferDamage(Hero attacker, Skill sourceSkill, Sign sourceSign, int damage) {
        if (attacker != null) {
            game.ui.printMsg("造成" + damage + "点伤害，");
        }
        else {
            game.ui.printMsg("受到" + damage + "点伤害,");
        }
        game.ui.sleepShortly();
        onBeforeSufferDamage(attacker, sourceSkill, sourceSign, damage);
        hp -= damage;
        event.onSufferDamage.sendRun(new HeroEvent_SufferDamage(attacker, sourceSkill, sourceSign, damage, this));
        onAfterSufferDamage(attacker, sourceSkill, sourceSign, damage);
        //任何伤害都要进行死亡判定
        boolean isAttackToDeath = checkDeath(); //死亡判定
        if (isAttackToDeath) {
            onDeath();
            game.events.onHeroDead.sendRun(new GameEvent_HeroDead(attacker, sourceSkill, sourceSign, damage, this)); //发布死亡通知
        }
        return isAttackToDeath;
    }

    /**
     * 当遭受到伤害前  注意！ attacker,sourceSkill,sourceSign 不属于同一个来源
     */
    public void onBeforeSufferDamage(Hero attacker, Skill sourceSkill, Sign sourceSign, int damage) {

    }

    /**
     * 当遭受到伤害后  注意！ attacker,sourceSkill,sourceSign 不属于同一个来源
     */
    public void onAfterSufferDamage(Hero attacker, Skill sourceSkill, Sign sourceSign, int damage) {

    }

    /**
     * 增加生命值并附带文案打印
     */
    public final void addHpWithPrint(int hpAdd) {
        int hpUpTo = getHpUpTo();
        if (hpUpTo > hpAdd) {
            hp += hpAdd;
            game.ui.printMsg("hp增加" + hpAdd + "点,当前" + hp + "。");
        }
        else {
            hp += hpUpTo;
            game.ui.printMsg("hp增加" + hpUpTo + "点,当前" + hp + "(已达上限)。");
        }
    }

    /**
     * 增加攻击力并打印文案
     */
    public final void addAtkWithPrint(int atkAdd) {
        atk += atkAdd;
        game.ui.printMsg("atk增加" + atkAdd + "点,当前" + atk + "。");
    }

    /**
     * 减少攻击力并打印文案
     */
    public final void dropAtkWithPrint(int atkDrop) {
        int atkDownTo = getAtkDownTo();
        if (atkDownTo > atkDrop) {
            atk -= atkDrop;
            game.ui.printMsg("atk减少" + atkDrop + "点,当前" + atk + "。");
        }
        else {
            atk -= atkDownTo;
            game.ui.printMsg("atk减少" + atkDownTo + "点,当前" + atk + "(已达下限)。");
        }
    }

    /**
     * 增加防御力并打印文案
     */
    public final void addDefWithPrint(int defAdd) {
        int defUpTo = getDefUpTo();
        if (defUpTo > defAdd) {
            def += defAdd;
            game.ui.printMsg("def增加" + defAdd + "点,当前" + def + "。");
        }
        else {
            def += defUpTo;
            game.ui.printMsg("def增加" + defUpTo + "点,当前" + def + "(已达上限)。");
        }
    }

    /**
     * 减少防御力并打印文案
     */
    public final void dropDefWithPrint(int defDrop) {
        if (def > defDrop) {
            def -= defDrop;
            game.ui.printMsg("def减少" + defDrop + "点,当前" + def + "。");
        }
        else {
            def = 0;
            game.ui.printMsg("def减少至0点。");
        }
    }

    /**
     * 获取当前生命值最多可增加的范围
     */
    public final int getHpUpTo() {
        return HP - hp;
    }

    /**
     * 获取当前攻击力最多可减少的范围
     */
    public final int getAtkDownTo() {
        return atk - HeroParam.ATK_MIN_LIMIT;
    }

    /**
     * 获取当前防御力最多可增加的范围
     */
    public final int getDefUpTo() {
        return HeroParam.DEF_MAX_LIMIT - def;
    }

    /**
     * 获取当前防御力最多可减少的范围(最小减少到0)
     */
    public final int getDefDownTo() {
        return def;
    }

    /**
     * 遗忘仇人
     */
    public final void clearEnemy() {
        state.recentEnemy = null;
    }

    /**
     * 记住仇人
     */
    public void setEnemy(@NonNull Hero enemy) {
        if (enemy.state.isAlive) {
            state.recentEnemy = enemy;
        }
    }

    /**
     * 遗忘猎物
     */
    public final void clearPrey() {
        state.recentPrey = null;
    }

    /**
     * 记住猎物
     */
    public void setPrey(@NonNull Hero prey) {
        if (prey.state.isAlive) {
            state.recentPrey = prey;
        }
    }

    /**
     * 遗忘世仇
     */
    public final void clearFeud() {
        state.recentEnemy = null;
        state.recentPrey = null;
    }

}
